package com.ztom.top100;

/**
 * 最小路径和
 * <p>
 * https://leetcode-cn.com/problems/minimum-path-sum/
 *
 * @author ZhangTao
 */
public class Code28MinPathSum {

    public int minPathSum3(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }

        return process(grid, 0, 0, grid.length - 1, grid[0].length - 1);
    }

    private int process(int[][] grid, int i, int j, int m, int n) {
        if (i == m && j == n) {
            return grid[i][j];
        }
        if (i == m) {
            // 只能向右走
            return grid[i][j] + process(grid, i, j + 1, m, n);
        }
        if (j == n) {
            // 只能往下走
            return grid[i][j] + process(grid, i + 1, j, m, n);
        }
        // 往下或往右走
        return grid[i][j] + Math.min(process(grid, i + 1, j, m, n), process(grid, i, j + 1, m, n));
    }

    public int minPathSum2(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m][n];
        dp[m - 1][n - 1] = grid[m - 1][n - 1];
        for (int j = n - 2; j >= 0; j--) {
            dp[m - 1][j] = grid[m - 1][j] + dp[m - 1][j + 1];
        }
        for (int i = m - 2; i >= 0; i--) {
            dp[i][n - 1] = grid[i][n - 1] + dp[i + 1][n - 1];
        }
        for (int i = m - 2; i >= 0; i--) {
            for (int j = n - 2; j >= 0; j--) {
                dp[i][j] = grid[i][j] + Math.min(dp[i + 1][j], dp[i][j + 1]);
            }
        }

        return dp[0][0];
    }

    /**
     * 数组压缩优化
     *
     * @param grid
     * @return
     */
    public int minPathSum(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }
        int m = grid.length;
        int n = grid[0].length;
        int[] dp = new int[n];
        // 最后一行
        dp[n - 1] = grid[m - 1][n - 1];
        for (int j = n - 2; j >= 0; j--) {
            dp[j] = grid[m - 1][j] + dp[j + 1];
        }

        for (int i = m - 2; i >= 0; i--) {
            // 每行最后一个
            dp[n - 1] = grid[i][n - 1] + dp[n - 1];
            // 从右往左推
            for (int j = n - 2; j >= 0; j--) {
                dp[j] = grid[i][j] + Math.min(dp[j], dp[j + 1]);
            }
        }

        return dp[0];
    }
}
